package com.spbdx.common.utils;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.spbdx.common.core.redis.RedisCache;
import com.spbdx.common.exception.ServiceException;
import com.spbdx.common.utils.http.HttpUtils;
import com.spbdx.common.utils.sign.Base64;
import com.spbdx.common.utils.spring.SpringUtils;
import com.spbdx.common.utils.support.WechatMsg;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.security.Security;
import java.util.*;
import java.util.concurrent.TimeUnit;


/**
 * Description TODO
 *
 * @author chenwei
 * @version 1.0
 * @date 2023/2/20 11:08
 */
public class WXUtils {

    private static final String WECHAT_TOKEN = "wechat_token:";

    private static RedisCache redisCache;
    //算法名
    private static final String KEY_ALGORITHM = "AES";
    //填充
    private static final String ALGORITHM_STR = "AES/CBC/PKCS7Padding";
    //密钥格式
    private static Key key;

    private static Cipher cipher;

    private static List<Map<String, String>> list = new ArrayList<>();

    //将传递过来的数据 用base64先行解密
    public static String decryptData(String encryptDataB64, String sessionKeyB64, String ivB64) {
        return new String(
                decryptOfDiyIV(
                        Base64.decode(encryptDataB64),
                        Base64.decode(sessionKeyB64),
                        Base64.decode(ivB64)
                )
        );
    }

    private static RedisCache getRedisCache() {
        if (Objects.isNull(redisCache)) {
            synchronized (WXUtils.class) {
                if (Objects.isNull(redisCache)) {
                    redisCache = SpringUtils.getBean("redisCache");
                }
            }
        }
        return redisCache;
    }

    private static void init(byte[] keyBytes) {
        // 如果密钥不足16位，那么就补足.  这个if 中的内容很重要
        int base = 16;
        if (keyBytes.length % base != 0) {
            int groups = keyBytes.length / base + (keyBytes.length % base != 0 ? 1 : 0);
            byte[] temp = new byte[groups * base];
            Arrays.fill(temp, (byte) 0);
            System.arraycopy(keyBytes, 0, temp, 0, keyBytes.length);
            keyBytes = temp;
        }
        // 初始化
        Security.addProvider(new BouncyCastleProvider());
        // 转化成JAVA的密钥格式
        key = new SecretKeySpec(keyBytes, KEY_ALGORITHM);
        try {
            // 初始化cipher
            cipher = Cipher.getInstance(ALGORITHM_STR, "BC");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 解密方法
     *
     * @param encryptedData 要解密的字符串
     * @param keyBytes      解密密钥
     * @param ivs           自定义对称解密算法初始向量 iv
     * @return 解密后的字节数组
     */
    private static byte[] decryptOfDiyIV(byte[] encryptedData, byte[] keyBytes, byte[] ivs) {
        byte[] encryptedText = null;
        init(keyBytes);
        try {
            cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ivs));
            encryptedText = cipher.doFinal(encryptedData);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return encryptedText;
    }

    /**
     * 凭证校验
     *
     * @param appid
     * @param secret
     * @param code
     * @return
     */
    public static JSONObject certificateVerification(String appid, String secret, String code) {
        String url = "https://api.weixin.qq.com/sns/jscode2session";
        String param = String.format("appid=%s&secret=%s&js_code=%s&grant_type=authorization_code", appid, secret, code);
        String res = HttpUtils.sendGet(url, param,null);
        System.out.println(res);
        JSONObject jsonObject = JSONObject.parse(res);
        return jsonObject;
    }

    /**
     * 获取access_token
     *
     * @param appid
     * @param secret
     * @return
     */
    public static String getAccessToken(String appid, String secret) {
        RedisCache redisCache = getRedisCache();
        String token = redisCache.getCacheObject(WECHAT_TOKEN + appid);
        if (StringUtils.isEmpty(token)) {
            synchronized (WXUtils.class) {
                if (StringUtils.isEmpty(token)) {
                    String url = "https://api.weixin.qq.com/cgi-bin/token";
                    String param = String.format("grant_type=client_credential&appid=%s&secret=%s", appid, secret);
                    String res = HttpUtils.sendGet(url, param,null);
                    JSONObject jsonObject = JSONObject.parse(res);
                    token = jsonObject.getString("access_token");
                    if (StringUtils.isEmpty(token)) {
                        throw new ServiceException("access_token=" + jsonObject.getString("errmsg"));
                    }
                    //默认7200秒 
                    Integer timeout = jsonObject.getInteger("expires_in") - 1000;
                    System.out.println("timeout=" + timeout);
                    redisCache.setCacheObject(WECHAT_TOKEN + appid, token, timeout, TimeUnit.SECONDS);
                }
            }
        }
        return token;
    }

    /**
     * 获取手机号
     *
     * @param appid
     * @param secret
     * @param code
     * @return
     */
    public static JSONObject getUserPhonenumber(String appid, String secret, String code) {
        String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + getAccessToken(appid, secret);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", code);
        String res = HttpUtils.sendPostJson(url, jsonObject.toJSONString(),null);
        JSONObject obj = JSONObject.parse(res);
        return obj;
    }


    /**
     * 微信公众号获取关注人员列表 每天500次上限
     *
     * @param appid
     * @param secret
     * @param nextOpenid
     */
    public static List<Map<String, String>> getWechatOpenid(String appid, String secret, String nextOpenid) {
        if (StringUtils.isEmpty(nextOpenid)) {
            nextOpenid = "";
            list = new ArrayList<>();
        }
        //https://developers.weixin.qq.com/doc/offiaccount/User_Management/Getting_a_User_List.html 公从号 一次拉取调用最多拉取10000个关注者的OpenID
//        String token = WXUtils.getAccessToken("wxe1e324ea74bad133", "0213ab60105ded38903223da251229f6");
        String url = "https://api.weixin.qq.com/cgi-bin/user/get?next_openid=" + nextOpenid + "&access_token=" + WXUtils.getAccessToken(appid, secret);
        String s = HttpUtils.sendPostJson(url, null,null);
        JSONObject users = JSONObject.parseObject(s);
        if (users.getLongValue("count") > 0) {
            JSONArray jsonArray = Optional.ofNullable(users.getJSONObject("data")).map(obj -> obj.getJSONArray("openid")).get();
            jsonArray.forEach(openid -> {
                String unionid = getUserInfo(appid, secret, String.valueOf(openid));
                Map<String, String> map = new HashMap();
                map.put("openid", String.valueOf(openid));
                map.put("unionid", unionid);
                list.add(map);
            });
            if (users.getLongValue("count") == 10000) {
                getWechatOpenid(appid, secret, users.getString("next_openid"));
            }
        }
        return list;
    }

    /**
     * 微信公众号获取关注人员信息 每天50万次上限
     *
     * @param appid
     * @param secret
     * @param openid
     */
    public static String getUserInfo(String appid, String secret, String openid) {
        String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + getAccessToken(appid, secret) + "&openid=" + openid + "&lang=zh_CN";
        String s = HttpUtils.sendPostJson(url, null,null);
        JSONObject jsonObject = JSONObject.parseObject(s);
        return jsonObject.getString("unionid");
    }


    /**
     * 推送消息
     *
     * @param wechatMsg
     */
    public static void sendMsg(WechatMsg wechatMsg) {
        String url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + getAccessToken(wechatMsg.getAppid(), wechatMsg.getSecret());
        JSONObject jsonObject = new JSONObject();
        JSONObject dataObj = new JSONObject();
        jsonObject.put("touser", wechatMsg.getOpenid());
        jsonObject.put("template_id", wechatMsg.getTemplateId());
        JSONObject miniprogramObject = new JSONObject();
        miniprogramObject.put("appid", wechatMsg.getUniAppid());
        miniprogramObject.put("pagepath", "");
        jsonObject.put("miniprogram", miniprogramObject);
        jsonObject.put("topcolor", "#FF0000");
        jsonObject.put("data", dataObj);

        //时间
        JSONObject time26Obj = new JSONObject();
        time26Obj.put("value", wechatMsg.getOrderTime());
        time26Obj.put("color", "#173177");
        dataObj.put("time26", time26Obj);

        //原因
        JSONObject thing27Obj = new JSONObject();
        thing27Obj.put("value", StringUtils.right(wechatMsg.getContent(), 20));
        thing27Obj.put("color", "#173177");
        dataObj.put("thing27", thing27Obj);

        //设备地址
        JSONObject thing16Obj = new JSONObject();
        thing16Obj.put("value", StringUtils.right(wechatMsg.getAddress(), 20));
        thing16Obj.put("color", "#173177");
        dataObj.put("thing16", thing16Obj);

        //报修地址
        JSONObject thing23Obj = new JSONObject();
        thing23Obj.put("value", StringUtils.right(wechatMsg.getAddress2(), 20));
        thing23Obj.put("color", "#173177");
        dataObj.put("thing23", thing23Obj);

        //客户姓名
        JSONObject nameObj = new JSONObject();
        nameObj.put("value", StringUtils.right(wechatMsg.getName(), 20));
        nameObj.put("color", "#173177");
        dataObj.put("thing8", nameObj);

        String res = HttpUtils.sendPostJson(url, jsonObject.toJSONString(),null);
        JSONObject resultObj = JSONObject.parseObject(res);
        System.out.println("messageRes" + resultObj.toString());
        if (0 != resultObj.getInteger("errcode")) {
            System.out.println("【服务号】消息推送错误：" + resultObj.getString("errmsg"));
//            l.error("【服务号】消息推送错误：" + resultObj.getString("errmsg"));
        }
    }

}
